package fmt_sfe

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"os"
	"strings"
)

func FmtStructFieldEnum(params []string) error {
	if len(params) < 2 {
		return fmt.Errorf("No file_path or no struct_name")
	}

	file_path, struct_name := params[0], params[1]

	f, err := os.Open("./" + file_path)
	if err != nil {
		return err
	}

	var fmted_buf, struct_buf bytes.Buffer

	unit, buf := (*FieldEnumUnit)(nil), bufio.NewReader(f)
	for {
		line, err := buf.ReadString('\n')
		if err != nil {
			if err == io.EOF {
				line += "\n"
				fmted_buf.WriteString(line)
				break
			}
			return err
		}

		line_ := strings.TrimSpace(line)

		// 找到已存在的目标枚举结构名 eg: type E[StructName]Field
		if strings.HasPrefix(line_, fmt.Sprintf("type E%sField", struct_name)) && (strings.Contains(line_, "int32") || strings.Contains(line_, "int")) {
			unit = &FieldEnumUnit{name: struct_name, adding: true}
			// 标记处当前结构
			//fmted_buf.WriteString(line)
			continue
		}

		// 找到目标结构体
		if strings.HasPrefix(line_, fmt.Sprintf("type %s struct", struct_name)) {
			if unit == nil {
				unit = &FieldEnumUnit{name: struct_name}
			}
			unit.inserting = true
			struct_buf.WriteString(line)
			continue
		}

		if unit != nil {
			switch {
			// 结束添加成员
			case unit.adding && strings.HasPrefix(line_, ")"):
				// 整合后写入全新的
				unit.adding = false
				continue
			case unit.inserting && strings.HasPrefix(line_, "}"):
				// 整合后写入全新的
				struct_buf.WriteString(line)

				fmted_buf.WriteString(unit.fmtstr())
				fmted_buf.WriteString(struct_buf.String())
				struct_buf = bytes.Buffer{}
				unit.inserting = false
				unit = nil
				continue
			// 添加现有的
			case unit.adding:
				if len(line_) > 0 {
					unit.addMember(line_)
				}
				continue
			// 添加更新的
			case unit.inserting:
				if len(line_) > 0 {
					unit.insertField(line_)
					struct_buf.WriteString(line)
				}
				continue
			}
			continue
		}
		fmted_buf.WriteString(line)
	}
	f.Close()

	// 写调整后的
	f, err = os.OpenFile("./"+file_path, os.O_RDWR|os.O_TRUNC, 0666)
	if err != nil {
		return err
	}
	fmted_buf.WriteTo(f)
	f.Close()

	return nil
}
